package brand

import (
	"context"
	"github.com/mozillazg/go-pinyin"
	"gorm.io/gorm"
	"mall/common/excption"
	constans "mall/services/product/rpc/consts"
	"mall/services/product/rpc/internal/domain/bo"
	"mall/services/product/rpc/internal/mapper"
	"mall/services/product/rpc/internal/mapper/entity"
	"strings"
	"time"
	"unicode"

	"mall/services/product/rpc/internal/svc"
	"mall/services/product/rpc/pb"

	"github.com/zeromicro/go-zero/core/logx"
)

type ModifyBrandLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewModifyBrandLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ModifyBrandLogic {
	return &ModifyBrandLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *ModifyBrandLogic) ModifyBrand(in *pb.ModifyBrandDTO) (*pb.EmptyObj, error) {
	// 1.check quest dto
	brandMapper, checkErr := l.checkRequestDTO(in)
	if checkErr != nil {
		return nil, checkErr
	}
	// 2.builder entity
	builderEntity, categoryBrandEntity := l.builderEntity(in)
	// 3.modify info
	saveErr := l.saveDB(brandMapper, builderEntity, categoryBrandEntity)
	if saveErr != nil {
		return nil, saveErr
	}
	// 4.return obj
	return &pb.EmptyObj{}, nil
}

func (l *ModifyBrandLogic) saveDB(brandMapper *mapper.BrandMapper, builderEntity *entity.BrandEntity,
	categoryBrandEntity entity.CategoryBrandEntity) error {

	return l.svcCtx.DBEngin.Transaction(func(tx *gorm.DB) error {
		// 3.1 modify brand info
		updateBrandErr := brandMapper.UpdateCtx(tx, builderEntity)
		if updateBrandErr != nil {
			return updateBrandErr
		}
		// 3.2 delete brand category
		categoryBrandMapper := mapper.NewCategoryBrandMapper(l.ctx)
		// 3.2 delete brand category
		deleteCategoryErr := categoryBrandMapper.DeleteCtx(tx, builderEntity.BrandId)
		if deleteCategoryErr != nil {
			return deleteCategoryErr
		}
		// 3.3
		insertCategoryErr := categoryBrandMapper.InsertCtx(tx, categoryBrandEntity)
		if insertCategoryErr != nil {
			return insertCategoryErr
		}
		return nil
	})
}

func (l *ModifyBrandLogic) checkRequestDTO(in *pb.ModifyBrandDTO) (*mapper.BrandMapper, error) {
	brandMapper := mapper.NewBrandMapper(l.ctx)
	brandBO := bo.BrandBO{BrandId: in.BrandId, NeStatus: constans.Delete}
	returnEntity, err := brandMapper.SelectOneCtx(l.svcCtx.DBEngin, brandBO)
	if err != nil {
		return nil, err
	}
	if returnEntity.BrandId <= 0 {
		return nil, excption.NewErrCode(constans.BrandNoExistErr)
	}
	name := in.Name
	if len(name) <= 0 {
		return brandMapper, nil
	}
	brandBO = bo.BrandBO{Name: in.Name, NeStatus: constans.Delete}
	brandEntity, err := brandMapper.SelectOneCtx(l.svcCtx.DBEngin, brandBO)
	if err != nil {
		return nil, err
	}
	if brandEntity.BrandId > 0 && brandEntity.BrandId != in.BrandId {
		return nil, excption.NewErrCode(constans.BrandNameRepeatErr)
	}
	if len(in.Name) < 0 {
		return brandMapper, nil
	}
	nameRuneArr := []rune(in.Name)
	if !(unicode.Is(unicode.Scripts["Han"], nameRuneArr[0]) || unicode.IsLetter(nameRuneArr[0])) {
		return nil, excption.NewErrCode(constans.BrandNameValidErr)
	}
	return brandMapper, nil
}

func (l *ModifyBrandLogic) builderEntity(in *pb.ModifyBrandDTO) (*entity.BrandEntity, entity.CategoryBrandEntity) {
	// 2.1 builder brand entity
	brandEntity := &entity.BrandEntity{}
	brandEntity.Name = in.Name
	brandEntity.Desc = in.Desc
	brandEntity.ImgUrl = in.ImgUrl
	brandEntity.BrandId = in.BrandId
	if len(in.Name) > 0 {
		nameRuneArr := []rune(in.Name)
		pinYinConf := pinyin.NewArgs()
		if unicode.Is(unicode.Scripts["Han"], nameRuneArr[0]) {
			pinYinConf.Style = pinyin.FIRST_LETTER
			brandEntity.FirstLetter = strings.ToUpper(pinyin.Pinyin(in.Name, pinYinConf)[0][0])
		} else if unicode.IsLetter(nameRuneArr[0]) {
			brandEntity.FirstLetter = string(nameRuneArr[0])
		}
	}
	brandEntity.Seq = int(in.Seq)
	brandEntity.Status = int64(in.Status)
	now := time.Now()
	brandEntity.UpdateTime = now
	// 2.2 save brand category
	categoryBrandEntity := entity.CategoryBrandEntity{}
	categoryBrandEntity.CategoryId = in.CategoryId
	categoryBrandEntity.UpdateTime = now
	categoryBrandEntity.BrandId = in.BrandId
	categoryBrandEntity.CreateTime = now
	return brandEntity, categoryBrandEntity
}
